home *** CD-ROM | disk | FTP | other *** search
- Subject: v11i083: Watcher system monitor program, Part02/02
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rs@uunet.UU.NET
-
- Submitted-by: Kenneth Ingham <ingham@charon.unm.edu>
- Posting-number: Volume 11, Issue 83
- Archive-name: watcher/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 2)."
- # Contents: Docs/Paper Docs/watcher.1 control.y defs.h
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f Docs/Paper -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"Docs/Paper\"
- else
- echo shar: Extracting \"Docs/Paper\" \(13821 characters\)
- sed "s/^X//" >Docs/Paper <<'END_OF_Docs/Paper'
- X.TI Keeping watch over the flocks
- X.TI by night (and day)
- X.AU 7
- XKenneth Ingham
- XUniversity of New Mexico Computing Center
- XDistributed Systems Group
- X2701 Campus NE
- XAlbuquerque, NM 87131
- X(505) 277-8044
- Xingham@charon.unm.edu or ucbvax!unmvax!charon!ingham
- X.AB
- XOver the last several years, the number of machines maintained by the
- XUniversity of New Mexico Computing Center has increased rapidly, yet
- Xthe number of system managers monitoring these systems has remained
- Xstatic. Consequently, the system managers were faced with the task of
- Xwatching more and more machines; since only one system manager is on
- Xcall at any time (known affectionately as "DOC"), this soon proved to
- Xbe an unacceptable situation. Shell scripts running every six hours
- Xgave some assistance; this was offset by the fact that the scripts
- Xgenerated a great deal of output indicating normal system operation,
- Xwhich the system manager still had to scan carefully for signs of
- Xtrouble. This paper describes \fIwatcher\fR, a flexible system monitor
- Xwhich watches the system more closely than the human system manager
- Xwhile generating less output for him to examine.
- X.sp
- XRunning more often than the above mentioned set of shell scripts,
- X\fIwatcher\fR is able to keep closer tabs on the system; since it
- Xdelivers only a list of potential problems, however, this extra
- Xmonitoring produces \fIno\fR corresponding increase in the demand on
- XDOC. No problems slip by unnoticed in the more concise output,
- Xleading to an improvement in overall system availability as well as the
- Xmore effective utilization of the system manager's time.
- X.BD
- X.SE 0. Acknowledgments (I couldn't have done it without you)
- XI would like to thank Leslie Gorsline for her assistance in the writing
- Xof this paper. Without her, this paper might not have been. Also
- Xthanks to the UNMCC distributed systems group for their comments that helped
- Ximprove \fIwatcher\fR.
- X.SE 1. Background (the problem)
- XThe computing facilities offered by the University of New Mexico
- XComputing Center (UNMCC) include three microvaxen, five large vaxen
- X(780 or bigger), and a Sequent B8000. In addition to these Unix/VMS
- Xmachines, the UNMCC Distributed Systems Group (DSG) monitors a number
- Xof the various microvaxen and sun workstations scattered across
- Xcampus. This duty falls to the DSG Programmer designated as "DOC", or
- X"DSG On Call", who receives his beeper based on a monthly rotation
- Xschedule.
- X.sp
- XIn the past, shell scripts running every six hours reported various
- Xsystem statistics to DOC, who then scanned the output for signs of
- Xpossible trouble. The output of these shell scripts became
- Xoverwhelming as the number of machines and potential problems grew;
- Xcorresponding to this increase in output was an increase in the amount
- Xof time that DOC had to spend reading this output. In addition, most
- Xof this output merely indicated normal system operation; potential
- Xproblems were buried amongst non-problems. Because of this, DOC could
- Xoften waste a tremendous amount of time wading through system status
- Xreports, time which can be better spent actually fixing system
- Xproblems.
- X.sp
- XUnix is equipped with many powerful tools for program development, but
- Xnone which simply watch the system for signs of trouble. Programs like
- X\fIps\fR and \fIdf\fR provide information regarding the current state
- Xof the machine, yet it still remains DOC's responsibility to interpret
- Xthis information and assess the health of the system at any given
- Xtime. This deficiency can be rectified by providing the
- Xsystem with the capacity to determine its own state of health, advising
- XDOC when it notices a problem which requires DOC's intervention.
- X.SE 2. Design Goals (devising the solution)
- XIn designing \fIwatcher\fR, the author closely examined just what DOC
- Xdoes in monitoring the system; just how \fIdoes\fR DOC spot potential
- Xtrouble in the DOC reports? These reports consist of output from \fIdf
- X-i\fR, \fIruptime\fR, \fIps -aux | sort\fR, and the tail of
- X\fIcronlog\fR, which usually only changes in the middle of the night.
- XIt was determined that DOC's task consisted primarily of scanning
- Xvarious numbers in this output, deciding whether or not they had
- Xexceeded an allowable maximum or minimum, or if the values had changed
- Xtoo much from the last time the command was run, assuming the last
- Xvalue is even remembered. Getting a computer to do this is more
- Xcomplicated than might seem at first glance, due to inconsistencies in
- Xthe location of pertinent information between runs of these commands.
- XFor instance, the process occupying the fifth line of \fIps -ax\fR
- Xmight next time appear on the eighth line; similarly, \fIuptime\fR does
- Xnot consistently put germane information in the same place on the line.
- X.sp
- XWhile flexibility is certainly a primary design consideration, it is
- Xnot the whole story. In order to improve DOC's effectiveness, the
- Xprogram should run frequently, roughly every two or three hours,
- Xcatching problems early (hopefully before they have affected
- Xthe users). Thus, the program should also be as silent as possible
- Xexcept when it detects a potential problem; any advantage DOC gains in
- Xusing \fIwatcher\fR would be eliminated if the program delivered an
- Xexceedingly verbose status report every two hours. \fIwatcher\fR's
- Xproblem reports should be exact and concise, leading DOC immediately to
- Xthe trouble.
- X.sp
- XThe problem of reducing the amount of output DOC must process can be
- Xapproached in different ways, including the redesign of the current
- Xshell scripts. A simple \fIawk\fR script can watch the output from
- X\fIdf\fR [1]. However, each command would require a custom tailored
- X\fIawk\fR script to look at it. This task grows more complicated as the
- Xnumber of programs running increases.
- XWhile a program could be written to
- Xgenerate these \fIawk\fR scripts, this process is needlessly complex;
- Xfor only a bit more work, an efficient C program such as
- X\fIwatcher\fR can be developed.
- X.SE 3. Design (actual implementation of the solution)
- XRun at intervals specified in \fIcrontab\fR, \fIwatcher\fR parses a
- Xcontrol file (./\fIwatcherfile\fR by default)
- Xwith a \fIyacc\fR generated parser, building a data structure
- Xcontaining all of the information from the file. The file contains the
- Xlist of commands \fIwatcher\fR
- Xshould run (the pipeline), output specifications
- Xfor each command (the output format), and the guidelines used in
- Xdetermining if something is amiss and should be reported to DOC (the
- Xchange format). A sample \fIwatcher\fR control file would look
- Xsomething like this (comment lines begin with a '#'):
- X.EX
- X# Here is the pipeline and its alias:
- X(df -i | /usr/ucb/tail +2) { df }
- X# the output format; this is a column output format:
- X $1-9 device%k $41-42 spaceused%d $64-65 inodesused%d:
- X# and the change format:
- X spaceused 15%;
- X spaceused 0 89;
- X inodesused 15%;
- X inodesused 0 49.
- X
- X# another command example:
- X(/usr/ucb/ruptime | fgrep -f UnmHosts) { ruptime }
- X# this is a relative output format
- X 2 status%s 1 machine%k 7 loadav%d:
- X# and another change format:
- X loadav 0 10;
- X status "up".
- X.NX
- XThe first entry causes \fIwatcher\fR to run the \fIdf\fR pipeline
- Xlisted in parentheses. When reporting problems, \fIwatcher\fR refers
- Xto this command by the alias provided in the braces; if no alias
- Xappears, \fIwatcher\fR uses the entire pipeline.
- X.sp
- XThe output format
- Xinstructs \fIwatcher\fR how to parse the output;
- Xcolumn format, indicated in the output format by \fBnum-num\fR,
- Xinstructs \fIwatcher\fR that the output should be parsed
- Xby columns, while relative format, denoted by a single integer, shows
- Xthat the output should be broken up by whitespaces.
- XThrough the convention \fBname%type\fR, the output format also names each
- Xfield, indicating whether the field is numeric, string, or
- Xkeyword, specified by \fBd\fR, \fBs\fR, or \fBk\fR respectively.
- XKeyword fields are
- Xused to match up corresponding output lines between runs. Thus
- X.EX
- X 41-42 spaceused%d
- X.NX
- Xindicates that this field, named \fBspaceused\fR, contains numeric
- Xinformation in columns 41-42, while
- X.EX
- X 2 status%s
- X.NX
- Xinforms \fIwatcher\fR that the second word (group of non-whitespace
- Xcharacters) on the line is a string field named \fBstatus\fR.
- XFor the \fIdf\fR example given above,
- X.EX
- XFilesystem kbytes used avail capacity iused ifree %iused Mounted on
- X/dev/hp1f 52431 39763 7424 84% 6937 9447 42% /develop
- X.NX
- X\fBdevice\fR would be \fI/dev/hp1f\fR, \fBspaceused\fR would be 84,
- Xand \fBinodesused\fR would be 42. Similarly, the output from the
- X\fIruptime\fR example, which looks like this
- X.EX
- Xcharon up 26+07:53, 17 users, load 3.12, 2.90, 2.66
- X.NX
- Xwould be broken at the following places:
- X.EX
- Xcharon | up | 26+07:53, | 17 | users, | load | 3.12, | 2.90, | 2.66,
- X.NX
- Xassigning "up" to \fBstatus\fR, and 3.12 to \fBloadav\fR.
- X.sp
- XThe name field also appears in the change format, designating allowable
- Xvalues for this field to have. These values can be specified as
- Xsingle character strings in the case of string fields; in the case of
- Xnumeric fields, the values take the form of either
- Xpercentage or absolute changes, or a minimum and maximum which delineate
- Xan acceptable range.
- XThus
- X.EX
- X inodesused 15%;
- X inodesused 0 49.
- X.NX
- Xsignifies that DOC should be notified if the field named \fBinodesused\fR
- Xincreases by more than 15% from the last run, or if it is outside the
- Xrange 0 to 49; similarly
- X.EX
- X status "up";
- X.NX
- Xinforms \fIwatcher\fR to notify DOC if the \fBstatus\fR field contains
- Xanything other than the word "up".
- X.sp
- XAs \fIwatcher\fR parses the output of a pipeline, it stores the
- Xpertinent parts of the output in a history file (by
- Xdefault, ./\fIwatcher.history\fR).
- XThe next time \fIwatcher\fR runs, it reads this file to provide
- Xcomparison values for the command. If a command is new (i.e. it has no
- Xpreviously-stored output in the history file), \fIwatcher\fR checks the
- Xfields which require no previous data, such as min-max fields, while
- Xstill storing \fIall\fR of the relevant information to the history file.
- XThus, the next time the new command is run, it will be an \fIold\fR command,
- Xand meaningful between-run comparisons can be made.
- X.sp
- XWhen \fIwatcher\fR
- Xdetects no problems with the system, DOC receives an empty mail message
- Xwith the subject "\fIhostname\fR had no problems at \fIdate\fR";
- Xthis is to insure that \fImail\fR is running correctly.
- XWhen it notices a problem which should be brought to DOC's attention,
- Xit mails the system problem report in a concise
- Xformat, explaining what is wrong and why.
- XThus, rather than the megabytes of shell script output that DOC
- Xused to receive and have to read,
- Xhe merely sees this when he reads his mail:
- X.EX
- XMail version 5.2 6/21/85. Type ? for help.
- X"/usr/spool/mail/ingham": 5 messages 5 new
- X N 1 root@charon.unm Sat Apr 11 16:00 8/212 "charon had no problems at Sat"
- X N 2 root@ariel.unm Sat Apr 11 16:00 8/208 "ariel had no problems at Sat "
- X N 3 root@geinah.unm Sat Apr 11 16:00 11/417 "System problem report for gei"
- X N 4 root@izar.unm Sat Apr 11 16:00 8/204 "izar had no problems at Sat A"
- X N 5 root@deimos.unm Sat Apr 11 16:00 8/212 "deimos had no problems at Sat"
- X.NX
- XThe letters indicating no problems can be immediately deleted, and DOC
- Xcan turn his attention to the letter indicating a
- Xsystem problems. A sample problem report
- Xwould look something like this:
- X.EX
- Xdf has a max/min value out of range:
- X/dev/hp0h 140488 111195 15244 91% 10145 28767 26% /usr
- Xwhere spaceused = 91.00; valid range 0.00 to 89.00.
- XAlso it had inodesused change by more than 10%.
- XPrevious value 20.00; current value 26.00.
- X.NX
- XNote that if a line has more than one indication of a problem, all
- Xanomalies are included in the report.
- XThis provides DOC with as much information as possible, allowing him
- Xto determine the problem quickly and devise
- Xa rapid fix (hopefully before users know something is amiss).
- X.sp
- X.SE 4. Results (how its helped us)
- X\fIwatcher\fR's primary advantage lies in the reduction of DOC's work
- Xload. It has taken over the more menial aspects of monitoring a system,
- Xtasks like reading and comparing numbers,
- Xgiving DOC more time to concentrate on bugs of a nature which
- X\fIwatcher\fR isn't set up to monitor, such as problems in the
- Xaccounting system.
- XDOC is apprised of potential problems quickly, and in
- Xsome cases can repair them in less time than simply
- Xreading the shell script output
- Xwould have taken.
- X.sp
- XThe ability to monitor changes between runs has also helped bring to our
- Xattention some
- Xproblems which were missed in the DOC reports. For example,
- Xdisk space on \fI/u2\fR on one of our machines jumped by more than 15%. Since
- Xthis jump did not force the total space used above 90%, at which point
- XDOC would have investigated the filesystem, it is unlikely
- Xthat DOC would have even noticed this sudden change. The facility to
- Xwatch for relative changes between runs enables DOC to catch problems in
- Xtheir infancy, and fix problems such as filesystems filling up too
- Xrapidly before they inconvenience the users.
- X.sp
- XSince the system manager specifies not only the commands \fIwatcher\fR will
- Xexecute and the time lapse between successive runs, but also the
- Xparameters which indicate system anomalies,
- X\fIwatcher\fR can easily be seen as a very flexible, general system
- Xmonitor. Its use at UNM has provided an increase in the
- Xproductivity of the system manager, which has led in turn to the
- Xincrease in the reliability and availability of the systems at UNMCC.
- X.SE 5. Availability (how to get one)
- X\fIwatcher\fR will be sent to the moderator of mod.sources after the
- Xconference is over.
- X.SE 6. References (you might also find this interesting)
- X.in +0.5i
- X.ti -0.5i
- X[1] Monitoring Free Disk Space, Rik Farrow, Wizard's Grabbag, \fIUnix
- XWorld\fR, Vol. IV, no. 3, pp. 86-87.
- X.in -0.5i
- END_OF_Docs/Paper
- if test 13821 -ne `wc -c <Docs/Paper`; then
- echo shar: \"Docs/Paper\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f Docs/watcher.1 -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"Docs/watcher.1\"
- else
- echo shar: Extracting \"Docs/watcher.1\" \(6175 characters\)
- sed "s/^X//" >Docs/watcher.1 <<'END_OF_Docs/watcher.1'
- X.de EX
- X.nf
- X.sp
- X.in +0.5i
- X..
- X.de NX
- X.sp
- X.in -0.5i
- X.ad
- X.fi
- X..
- X.TH WATCHER 1 "April 10, 1987"
- X.UC 6
- X.ad
- X.SH NAME
- Xwatcher \- system monitoring program
- X.SH SYNOPSIS
- X.B watcher
- X[ \-p] [ \-v ]
- X[ \-h histfile ] [ \-f controlfile ]
- X.SH DESCRIPTION
- X.I Watcher
- Xis a program to watch the system, reporting only when it finds something
- Xamiss.
- X.I Watcher
- Xreads commands from
- X.I controlfile
- Xto determine what to watch, the output format of the commands it is to
- Xrun, and the acceptable limits for the output of those commands.
- XIf no
- X.B \-f
- Xoption is present, the program looks first for `watcherfile',
- Xthen `Watcherfile' to use as the input.
- X.PP
- XThe
- X.B \-h histfile
- Xflag tells watcher what file to use as a history file for comparisons
- Xbetween runs. The default is `watcher.history'.
- X.PP
- XThe
- X.B \-p
- Xoption has
- X.I watcher
- Xpretty print the control file. This is useful to make sure that watcher
- Xis parsing the file the way expected, and to provide a prettier version
- Xof the control file to use (i.e. it is of limited use).
- X.PP
- XThe
- X.B \-v
- Xoption tells watcher to be verbose as it is running. It will print out
- Xvarious information about where it is looking for the files that it
- Xuses, the commands that it is executing, and the output from these
- Xcommands. This option is mainly of use when debugging control files or
- Xdebugging watcher itself.
- X.PP
- X.I Watcherfile
- Xcontains a sequence of entries that specify the commands to be executed,
- Xthe output format of those commands, and what changes should be
- Xreported. The format of the control file is one or more of the
- Xfollowing:
- X.EX
- X( <pipeline> ) { <alias> }
- X <output format> :
- X <change format>.
- X.NX
- XA <pipeline> is a series of commands joined together with pipes ('|').
- XThis command is executed and the output parsed according to the output
- Xformat specified. It is then checked against the change format for
- Xpotential problems. An <alias> is optional; it is used when identifying
- Xthe command in the report of problems encountered. If there is no
- Xalias, the entire pipeline is used. The reason for using an alias is
- Xto keep the report clean; the pipelines tend to be long and messy.
- X.PP
- XAn <output format> is either a column format or a relative format. A
- Xcolumn format is one or more of the following:
- X.EX
- X <start> - <end> <name> % <type>
- X.NX
- XWhere <start> is the first column containing the information to be compared and
- X<end> is the last one. <name> is the name of the field. This name is
- Xmatched with the names in the change format to identify where in the
- Xoutput the appropriate information is. <type> is either "d", "s", or
- X"k" specifying numeric or string data, or a keyword which is used in
- Xmatching output from the various programs between runs.
- X.PP
- XRelative formats are one or more of the following:
- X.EX
- X<field> <name> % <type>
- X.NX
- XWhere <field> is the field on the line (a field is defined as a sequence
- Xof non-whitespace surrounded by whitespace). <name> and <type> are the
- Xsame as for above.
- X.PP
- XA change format consists of various names and what changes are
- Xallowable. Change format entries are separated by semicolons (';'). The
- Xlist of change formats is terminated by a period ('.'). A semicolon
- Xdoes not follow the last change format.
- X.I Watcher
- Xknows about 4 types of changes. It can compare the output (numeric)
- Xto the previous value and calculate the percentage change. If the
- Xchange is greater that a set amount, a message is generated. The syntax
- Xof this format is:
- X.EX
- X <name> <value> %
- X.NX
- Xwhere <name> is a name matching a name in the output format and <value
- Xis the maximum percentage change which is allowed before a report is
- Xissued.
- X.PP
- XVery similar to the percentage change is the absolute change. The only
- Xdifference is that a percentage is not calculated. The difference is
- Xcalculated and compared to the value given. Values greater that what is
- Xprovided are reported. The syntax is:
- X.EX
- X <name> <value>
- X.NX
- X.PP
- XA maximum and minimum may be specified for numeric data also. This is
- Xuseful for only numeric data. The format for this is:
- X.EX
- X <name> <max> <min>
- X.NX
- X.PP
- X.I Watcher
- Xcan also watch for string values changing from a given value to any
- Xother value. This syntax is:
- X.EX
- X <name> "<value>"
- X.NX
- X.PP
- XA sample control file is provided below:
- X.EX
- X(df -i | /usr/ucb/tail +2) { df }
- X 1-9 filesystem%k 41-42 spaceused%d 64-65 inodesused%d 1-9 device%k:
- X spaceused 15%;
- X spaceused 0 89;
- X inodesused 15%;
- X inodesused 0 49.
- X(/usr/ucb/ruptime | fgrep -f UnmHosts) { ruptime }
- X 2 status%s 1 machine%k 7 loadav%d:
- X loadav 0 10;
- X status "up".
- X(ps -aux | fgrep -v -f Daemons | /usr/ucb/tail +2) { 'ps with no daemons' }
- X 9-14 pid%k 16-19 percentcpu%d 42-45 cputime%d:
- X cputime 0 10.
- X.NX
- XNote that there is no order for the output format specifiers; the second
- Xfield may be specified before the first.
- X.PP
- XAll names are of arbitrary length, start with [a-zA-Z] and contain no
- Xwhite space unless enclosed in tics ("'").
- X.PP
- XThe pipeline is executed by
- X.I popen(3),
- Xwhich uses
- X.I sh(1)
- Xto expand the command; therefore shell metacharacters may be used.
- X.PP
- XThe control file may have comments in it. Comments are delimited by a #
- Xon the left and a newline on the right.
- X.SH FILES
- X.nf
- XWatcherfile or watcherfile default control file.
- Xwatcher.history default file containing results of previous run.
- X.SH AUTHOR
- X.nf
- XKenneth Ingham
- XUniversity of New Mexico Computing Center
- X2701 Campus NE
- XAlbuquerque, NM, 87131
- Xingham@charon.unm.edu
- X.SH "SEE ALSO"
- Xpopen(3), sh(1),
- X.I Keeping Watch over the
- X.I Flocks by Night (and day)
- Xby Kenneth Ingham, Summer 1987 Usenix proceedings.
- X.SH DIAGNOSTICS
- XFiles which can't be opened cause a message about which files couldn't
- Xbe found and the program exits.
- X.sp
- XThere are various syntax errors when parsing the controlfile. These
- Xalso cause an exit.
- X.sp
- X.I Watcher
- Xcomplains when output does not parse according to the format
- Xprovided. It will continue to look at the rest of the output.
- X.SH BUGS
- XSyntax errors in control file are not easy to find based on the error
- Xmessages.
- X.sp
- XDoesn't warn when a string variable has been selected for a numeric
- Xcomparison.
- X.sp
- XOnly notices changes which get bigger; things which suddenly
- Xdrop will not be noticed.
- END_OF_Docs/watcher.1
- if test 6175 -ne `wc -c <Docs/watcher.1`; then
- echo shar: \"Docs/watcher.1\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f control.y -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"control.y\"
- else
- echo shar: Extracting \"control.y\" \(6895 characters\)
- sed "s/^X//" >control.y <<'END_OF_control.y'
- X/*
- X the grammer describing the control file for watcher.
- X
- X Kenneth Ingham
- X
- X Copyright (C) 1987 The University of New Mexico
- X*/
- X
- X%token PIPELINE NUMBER STRING
- X%start command
- X
- X%{
- X#include "defs.h"
- X#define SMAXMIN struct max_min_st
- X#define SOUTFMT struct out_fmt_st
- X#define SCOLOUT struct col_out_st
- X#define SRELOUT struct rel_out_st
- X#define SCMD struct cmd_st
- X#define SCH struct change_fmt_st
- Xextern char *strval, ostrval[], pipeline[];
- Xextern int intval, ointval;
- Xextern struct cmd_st *clist;
- Xint out_type;
- Xchar alias[MAX_STR];
- Xunion out_fmt_u key;
- X%}
- X
- X%%
- X/*
- X THE PARSER DESCRIPTION (read aloud to the beginning of
- X _Also_sprach_Zarathustra_)
- X
- X As things are discovered, they are put into the linked list structure
- X detailed in defs.h. Some error checking is done, but the messages
- X leave a bit to be desired. Yacc and I didn't get along too well in
- X figuring out how to handle errors.
- X
- X Assuming that pointers will fit into YYSTYPE (int on 4.3 vax).
- X Should use yacc's union facility.
- X*/
- X
- Xcommand : one_command
- X {
- X if (clist == NULL)
- X clist = (SCMD *) $1;
- X }
- X | command one_command
- X {
- X SCMD *p;
- X
- X if (clist != NULL) {
- X for (p=clist; p->next!=NULL; p=p->next)
- X ;
- X p->next = (SCMD *)$2;
- X }
- X else
- X clist = (SCMD *)$1;
- X }
- X | error '.'
- X {
- X fprintf(stderr, "Command error near ");
- X fprintf(stderr, "'%s'\n", pipeline);
- X fprintf(stderr,"Last string read was '%s'\n", strval);
- X }
- X ;
- X
- Xone_command : PIPELINE alias out_fmt ':' change_fmt '.'
- X {
- X SCMD *p;
- X
- X p = (SCMD *) malloc(sizeof(SCMD));
- X if (p == NULL) {
- X fprintf(stderr,"malloc error\n");
- X exit(1);
- X }
- X p->pipeline = malloc((unsigned)strlen(pipeline)+1);
- X if (p->pipeline == NULL) {
- X fprintf(stderr,"malloc error\n");
- X exit(1);
- X }
- X (void) strcpy(p->pipeline, pipeline);
- X
- X if (alias[0]) {
- X p->alias = malloc((unsigned)strlen(alias)+1);
- X if (p->alias == NULL) {
- X fprintf(stderr,"malloc error\n");
- X exit(1);
- X }
- X (void) strcpy(p->alias, alias);
- X }
- X else
- X p->alias = NULL;
- X
- X p->change_fmt = (SCH *)$5;
- X p->next = NULL;
- X p->out_type = out_type;
- X if (out_type == RELATIVE) {
- X p->out_fmt.rel_fmt = (SRELOUT *)$3;
- X p->key.rel_fmt = key.rel_fmt;
- X }
- X else { /* it better be column */
- X p->out_fmt.col_fmt = (SCOLOUT *)$3;
- X p->key.col_fmt = key.col_fmt;
- X }
- X
- X key.rel_fmt = NULL;
- X $$ = (int)p;
- X }
- X ;
- X
- Xout_fmt : rel_out_fmt
- X {
- X out_type = RELATIVE;
- X $$ = $1;
- X }
- X | col_out_fmt
- X {
- X out_type = COLUMN;
- X $$ = $1;
- X }
- X | error '.'
- X {
- X fprintf(stderr,"Output format error on ");
- X fprintf(stderr,"'%s'\n", pipeline);
- X fprintf(stderr,"Last string read was '%s'\n",
- X strval);
- X }
- X ;
- X
- Xchange_fmt : one_change_fmt
- X | change_fmt ';' one_change_fmt
- X {
- X SCH *p;
- X
- X for (p=(SCH *)$1; p->next != NULL; p = p->next)
- X ;
- X
- X p->next = (SCH *)$3;
- X
- X $$ = (int)$1;
- X }
- X ;
- X
- Xone_change_fmt : pct_change_fmt
- X { $$ = $1; } /* Is this default? */
- X | abs_change_fmt
- X { $$ = $1; }
- X | max_min_fmt
- X { $$ = $1; }
- X | str_change_fmt
- X { $$ = $1; }
- X | error '.'
- X {
- X fprintf(stderr,"Unknown change format type ");
- X fprintf(stderr,"on '%s'\n", pipeline);
- X fprintf(stderr,"Last string read '%s'\n", strval);
- X }
- X ;
- X
- Xrel_out_fmt : one_rel_fmt
- X | rel_out_fmt one_rel_fmt
- X {
- X SRELOUT *p;
- X
- X for (p=(SRELOUT *)$1;p->next != NULL; p=p->next)
- X ;
- X p->next = (SRELOUT *)$2;
- X $$ = (int)$1;
- X }
- X ;
- X
- Xcol_out_fmt : one_col_fmt
- X | col_out_fmt one_col_fmt
- X {
- X SCOLOUT *p;
- X
- X for (p=(SCOLOUT *)$1;p->next != NULL; p=p->next)
- X ;
- X p->next = (SCOLOUT *)$2;
- X $$ = (int)$1;
- X }
- X /*
- X | error '.'
- X {
- X fprintf(stderr,"Column output format error\n");
- X fprintf(stderr,"Last string read '%s'\n", strval);
- X }
- X */
- X ;
- X
- Xone_rel_fmt : NUMBER STRING '%' STRING
- X {
- X extern int parse_error;
- X SRELOUT *p;
- X
- X p = (SRELOUT *) malloc(sizeof(SRELOUT));
- X p->name = malloc((unsigned)strlen(ostrval)+1);
- X (void) strcpy(p->name, ostrval);
- X p->field = intval;
- X p->next = NULL;
- X
- X if (strval[1] != '\0') {
- X fprintf(stderr,"%s: Invalid type specifier '%s'.\n",
- X NAME, strval);
- X parse_error = True;
- X $$ = (int)p;
- X }
- X
- X switch (*strval) {
- X case 'd':
- X case 'f':
- X p->type = NUM;
- X break;
- X case 's':
- X p->type = STRING;
- X break;
- X case 'k':
- X p->type = KEY;
- X key.rel_fmt = p;
- X break;
- X default:
- X fprintf(stderr,"%s: Invalid type specifier '%s'.\n",
- X NAME, strval);
- X parse_error = True;
- X }
- X
- X $$ = (int) p;
- X }
- X ;
- X
- Xone_col_fmt : NUMBER '-' NUMBER STRING '%' STRING
- X {
- X extern int parse_error;
- X SCOLOUT *p;
- X
- X p = (SCOLOUT *) malloc(sizeof(SCOLOUT));
- X p->name = malloc((unsigned)strlen(ostrval)+1);
- X (void) strcpy(p->name, ostrval);
- X p->start = ointval;
- X p->end = intval;
- X p->next = NULL;
- X
- X if (ointval >= intval) {
- X fprintf(stderr,"%s: start %d larger than end %d!\n", NAME, ointval, intval);
- X parse_error = True;
- X $$ = (int)p;
- X }
- X
- X if (strval[1] != '\0') {
- X fprintf(stderr,"%s: Invalid %s '%s'.\n",
- X NAME, "type specifier", strval);
- X parse_error = True;
- X $$ = (int)p;
- X }
- X
- X switch (*strval) {
- X case 'd':
- X case 'f':
- X p->type = NUM;
- X break;
- X case 's':
- X p->type = STRING;
- X break;
- X case 'k':
- X p->type = KEY;
- X key.col_fmt = p;
- X break;
- X default:
- X fprintf(stderr,"%s: %s '%s'.\n",
- X NAME,
- X "Bad type specifier",
- X strval);
- X parse_error = True;
- X }
- X $$ = (int) p;
- X }
- X ;
- X
- Xpct_change_fmt : STRING NUMBER '%'
- X {
- X SCH *p;
- X
- X p = (SCH *) malloc(sizeof(SCH));
- X p->name = malloc((unsigned)strlen(strval)+1);
- X (void) strcpy(p->name, strval);
- X p->fmt.percent = (float)intval / 100;
- X p->type = PERCENT;
- X
- X $$ = (int) p;
- X }
- X ;
- X
- Xabs_change_fmt : STRING NUMBER
- X {
- X SCH *p;
- X
- X p = (SCH *) malloc(sizeof(SCH));
- X p->name = malloc((unsigned) strlen(strval)+1);
- X (void) strcpy(p->name, strval);
- X p->fmt.abs_amount = intval;
- X p->type = ABSOLUTE;
- X
- X $$ = (int) p;
- X }
- X ;
- X
- Xmax_min_fmt : STRING NUMBER NUMBER
- X {
- X SCH *p;
- X
- X p = (SCH *) malloc(sizeof(SCH));
- X p->name = malloc((unsigned)strlen(strval)+1);
- X (void) strcpy(p->name, strval);
- X p->fmt.max_min.max = intval;
- X p->fmt.max_min.min = ointval;
- X p->type = MAX_MIN;
- X
- X $$ = (int) p;
- X }
- X ;
- X
- Xstr_change_fmt : STRING '"' STRING '"'
- X {
- X SCH *p;
- X
- X p = (SCH *) malloc(sizeof(SCH));
- X p->name = malloc((unsigned)strlen(ostrval)+1);
- X (void) strcpy(p->name, ostrval);
- X p->fmt.str_value = malloc((unsigned)strlen(strval)+1);
- X (void) strcpy(p->fmt.str_value, strval);
- X p->type = STRING;
- X
- X $$ = (int) p;
- X }
- X ;
- X
- Xalias : '{' STRING '}'
- X { (void) strcpy(alias, strval); }
- X | empty
- X { alias[0] = '\0'; }
- X ;
- X
- Xempty : ;
- END_OF_control.y
- if test 6895 -ne `wc -c <control.y`; then
- echo shar: \"control.y\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f defs.h -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"defs.h\"
- else
- echo shar: Extracting \"defs.h\" \(4706 characters\)
- sed "s/^X//" >defs.h <<'END_OF_defs.h'
- X/*
- X Structure definitions, included files needed and useful constants for
- X Watcher.
- X
- X Kenneth Ingham
- X
- X Copyright (C) 1987 The University of New Mexico
- X*/
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X
- X#ifdef BSD
- X#include <strings.h>
- X#else
- X#include <string.h>
- X#endif
- X
- X#include <signal.h>
- X#include "y.tab.h"
- X
- X#define False 0
- X#define True 1
- X#define NAME "watcher"
- X#define MAX_STR 256
- X#define DEF_CONTROL "watcherfile"
- X#define DEF_CONTROL2 "Watcherfile"
- X#define DEF_HISTFILE "watcher.history"
- X#define MAX_NAME 16
- X#define MAX_VEC 100
- X
- X#define INT 1
- X#define FLOAT 2
- X#define PERCENT 3
- X#define ABSOLUTE 4
- X#define MAX_MIN 5
- X#define RELATIVE 6
- X#define COLUMN 7
- X#define NUM 8 /* really needs to be replaced by int or float */
- X#define KEY 9
- X
- X/*
- X below lie the structure definitions for all of the linked lists used
- X in watcher. Make piece with your god before venturing onward
- X*/
- X
- X/*
- X what a column output fromat entry looks like:
- X*/
- Xstruct col_out_st {
- X char *name; /* name of output field */
- X int start; /* where it starts... */
- X int end; /* ... and ends */
- X int type; /* what type of data to find there */
- X struct col_out_st *next; /* and the next in the list is... */
- X};
- X
- X/*
- X and a relative output format...
- X*/
- Xstruct rel_out_st {
- X char *name; /* name of output field */
- X int field; /* Which field to look in for it */
- X int type; /* what type of data to find there */
- X struct rel_out_st *next; /* and the next in the list */
- X};
- X
- X/*
- X types of change formats; all joined in a union later.
- X*/
- Xstruct max_min_st {
- X float max; /* max allowable value... */
- X float min; /* ...and the min */
- X};
- X
- Xunion fmt_u {
- X float percent; /* percent change */
- X float abs_amount; /* absolute change */
- X struct max_min_st max_min; /* max and min */
- X char *str_value; /* what the string should be */
- X};
- X
- X/*
- X the actual structure describing how things are allowed to change.
- X*/
- Xstruct change_fmt_st {
- X char *name; /* name of the field this pertains to */
- X int type; /* what type of change */
- X union fmt_u fmt; /* the format, depending on type */
- X struct change_fmt_st *next; /* and of course the next in the list */
- X};
- X
- X/*
- X for the various types of output formats:
- X*/
- Xunion out_fmt_u {
- X struct rel_out_st *rel_fmt; /* a relative output format (fields) */
- X struct col_out_st *col_fmt; /* or one that uses columns */
- X};
- X
- X/*
- X what we are all about: the command structure. Here we bring it all
- X together and have something to work with (luckily the subroutines are
- X also set up in a similar heirarchy and we can pass various parts of
- X the linked lists to them and they don't care about the "upper" parts.
- X*/
- Xstruct cmd_st {
- X char *pipeline; /* the pipeline to execute */
- X char *alias; /* a name to use when refering to it */
- X int out_type; /* what type of output format used */
- X union out_fmt_u out_fmt; /* the output format */
- X union out_fmt_u key; /* what to key on for btwn run cmps */
- X struct change_fmt_st *change_fmt;/*the things to watch for changes */
- X struct cmd_st *next; /* and of course the next in the list */
- X};
- X
- X/*
- X now we get into the structures for the history linked list...
- X*/
- X
- X/*
- X a way of storing any data type:
- X*/
- Xunion all_u {
- X char *strval;
- X int intval;
- X float floatval;
- X};
- X
- X/*
- X which is used here where we hold the value for a specified key value
- X from the previous output.
- X*/
- Xstruct val_st {
- X char *name; /* output field name */
- X int type; /* what type of data in the union */
- X union all_u val; /* ... the data (wow!) */
- X struct val_st *next; /* and where would we be without a next one? */
- X};
- X
- X/*
- X for each line in the output of a command, we grab the key and store
- X all of the values obtained from the line. Here is how it is done.
- X*/
- Xstruct key_st {
- X char *key_value; /* value for the key (could you guess?) */
- X struct val_st *vals; /* the various interesting parts of the line */
- X struct key_st *next; /* and of course the next one */
- X};
- X
- X/*
- X inally we come to the reaon for all of the above structures. This is
- X how previous commands are stored once they have been read in from the
- X history file.
- X*/
- Xstruct old_cmd_st {
- X char *pipeline; /* the pipeline executed */
- X struct key_st *keys; /* the keys and their useful parts */
- X struct old_cmd_st *next; /* and the next pipeline... */
- X};
- X
- X/*
- X way of converting between type stored in struct and char for a
- X person's use. This works on the cmd_st.out_type values.
- X*/
- X#define TCHAR(i) (i==STRING ? 's' : (i == KEY ? 'k' : 'd'))
- X
- Xchar *malloc(); /* really should switch back to malloc */
- Xchar *get_rel_field(), *get_col_field();
- Xdouble atof();
- Xstruct old_cmd_st *find_prev_cmd();
- X
- X/* bezerkeley vs system v differences... */
- X#ifdef SYSV
- X#define index strchr
- X#endif
- END_OF_defs.h
- if test 4706 -ne `wc -c <defs.h`; then
- echo shar: \"defs.h\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- echo shar: End of archive 2 \(of 2\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked both archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-